home *** CD-ROM | disk | FTP | other *** search
- ;History:1045,7,17
- test_device equ 0
- .xlist
- include memory.def
-
-
- bufseg segment public
-
- next_buffer dw ?
-
- extrn toptop: word
- extrn topbot: word
- extrn bottop: word
- extrn botbot: word
-
- extrn memsize: word
-
- extrn bufseg_size: word
-
- bufseg ends
-
-
- data segment byte public
-
- extrn phd_seg: word
-
- public textseg
- textseg dw ?
-
- first_buffer dw ? ;segment of first buffer
- last_para dw ? ;segment after highest buffer
- limit_para dw ? ;segment after highest available.
-
- fcb_struc struc
- fcb_drive db 0
- fcb_fname db ' '
- fcb_ext db ' '
- fcb_curblk dw 0
- fcb_recsz dw 0
- fcb_filsz dw 0,0
- fcb_date dw 0
- fcb_time dw 0
- fcb_res dd ?,?
- fcb_currec db 0
- fcb_ranrec dw 0,0
- fcb_struc ends
-
- device_header struc
- device_next dd ?
- device_attr dw ?
- device_strategy dw ?
- device_intr dw ?
- device_name db ' '
- device_header ends
-
- ;static request header.
- srh_struc struc
- srh_len db ?
- srh_unit db ?
- srh_cmd db ?
- srh_status dw ?
- srh_res dd ?,?
- srh_struc ends
-
-
- ;static request header for reading and writing.
- srh_rw struc
- db (size srh_struc) dup(?)
- crw_media db ?
- crw_taddr dd ?
- crw_cnt dw ?
- crw_start dw ?
- srh_rw ends
-
-
- ;static request header for nondestructive read no wait.
- srh_ic struc
- db (size srh_struc) dup(?)
- cic_char db ?
- srh_ic ends
-
- segofs struc
- offs dw ?
- segm dw ?
- segofs ends
-
- nul_fcb fcb_struc <0,'NUL ',' '>
-
- our_device_name db '@',0
-
- their_end dd ?
-
- eof_mark db ']'
-
- extrn inverse_flag: byte
-
- db 256 dup(?)
- mystack label byte
-
- md_ctab label word
- dw md_unk ; initialize
- dw md_unk ; media check
- dw md_unk ; build bpb
- dw md_unk ; input control string
- dw md_in ; input
- dw md_ichk ; input check (buffer status)
- dw md_istat ; input status
- dw md_succ ; input flush
- dw md_out ; output
- dw md_out ; output with verify
- dw md_ostat ; output status
- dw md_succ ; output buffer flush
- dw md_unk ; output control string
-
- crlf_string db 0dh,0ah
-
- data ends
-
-
- code segment byte public
- ;all the routines in this segment are entered with ds=data, es=data
- assume cs:code, ds:data, es:data, ss:data
-
- ;the following externs are in 'memory'
- extrn read_mark: near
- extrn del_to_mark: near
-
- ;the following externs are in 'redisplay'
- extrn redisplay: near
- extrn paint_screen: near
-
- extrn init_entry: near
- extrn uninit_exit: near
-
- extrn abort_fatal: near ;fatal error handler
-
-
- our_sp dw ?
- our_ss dw ?
- ptrsav dd ?
- their_sp dw ?
- their_ss dw ?
-
- our_device device_header<-1,8000h, md_strat, md_intr, '@ '>
-
- lf_flag db 0 ;=1 if we should return LF next input.
-
- parameters dw 0
- dw 80h, ?
- dw 5ch, ?
- dw 6ch, ?
-
- copy_to_dioa:
- ;enter with si, cx->command.
- ;exit with cs:phd_dioa set to the string.
- push es
- mov es,phd_seg ;copy the command to phd_dioa+1
- mov di,80h+1
- if 0
- mov ax,3700h ;get the switch char.
- int 21h
- mov al,dl
- stosb
- mov al,'C' ;store -C or /C.
- stosb
- endif
- rep movsb
- mov al,CR ;store the terminating CR.
- stosb
- sub di,80h+1+1 ;don't count the CR.
- mov ax,di
- mov es:[80h],al ;store the count.
- pop es ;restore es.
- ret
-
-
- public execute_program
- execute_program:
- ;enter with si, cx->path of filter to execute, di ->null terminated filename.
- ;exit with ax=return result.
- push di
- call copy_to_dioa
- call init_device
- pop di
- call actually_execute
- push ax
- call uninit_device
- pop ax
- ret
-
-
- public execute_filter
- execute_filter:
- ;enter with:
- ; si, cx->path of filter to execute,
- ; al=mark to filter to.
- ; di ->null terminated filename.
- ;exit with ax=return result.
- mov eof_mark,al
-
- push di
- call copy_to_dioa
- call init_device
- pop di
-
- mov bx,0 ;get a copy of stdin.
- mov ah,45h
- int 21h
- push ax ;remember the old handle.
-
- mov bx,1 ;get a copy of stdout.
- mov ah,45h
- int 21h
- push ax ;remember the old handle.
-
- mov dx,offset our_device_name
- mov ax,3d02h ;open for read/write.
- int 21h
- mov bx,ax ;remember the handle.
-
- mov cx,0 ;force stdin to the per device.
- mov ah,46h
- int 21h
-
- mov cx,1 ;force stdout to the per device.
- mov ah,46h
- int 21h
-
- mov ah,3eh ;close the original handle.
- int 21h
-
- mov bx,0 ;set stdin to raw.
- mov ax,4400h ;get the device info.
- int 21h
- mov dh,0
- or dl,20h ;set to raw mode.
- mov ax,4401h ;set the device info.
- int 21h
-
- call actually_execute
-
- mov dx,ax
-
- mov bx,1 ;close stdout.
- mov ah,3eh
- int 21h
-
- pop bx ;unredirect stdout.
- mov ah,46h
- mov cx,1
- int 21h
-
- mov bx,0 ;close stdin.
- mov ah,3eh
- int 21h
-
- pop bx ;unredirect stdin.
- mov cx,0
- mov ah,46h
- int 21h
-
- push dx ;save the result code.
- call uninit_device
- pop ax
- ret
-
-
- actually_execute:
- ;enter with di -> filename, cs:phd_dioa = arguments.
- push di
- call uninit_exit
- pop di
-
- push ds
- push es
-
- push di
- call compact_buffers ;make room for the program.
- pop di
-
- mov ds,dx ;get the para of the last buffer.
- assume ds:bufseg
- mov bx,dx ;remember the last buffer here.
-
- call buffer_paragraphs
- add bx,cx ;compute the first free segment.
-
- mov dx,phd_seg ;subtract off the allocated segment.
- sub bx,dx
- mov es,dx ;get es=allocated segment.
- assume es:nothing
-
- mov ah,4ah ;reduce ourself in size.
- int 21h
-
- mov our_sp,sp ;remember our stack.
- mov our_ss,ss
-
- mov ds,phd_seg ;move ds first because we need ds.
- assume ds:nothing
- mov es,phd_seg
- assume es:nothing
-
- mov dx,di ;set up to execute the program.
-
- mov ax,2901h ;parse fcb1.
- mov si,81h ;->phd_sdioa.
- mov di,5ch ;->phd_fcb1
- int 21h
-
- mov ax,2901h ;parse fcb2.
- mov di,6ch ;->phd_fcb2.
- int 21h
-
- push ss ;ss:dx -> filename to execute.
- pop ds
- assume ds:data
- push cs
- pop es
- assume es:code
- mov bx,offset parameters
- mov ax,phd_seg
- mov es:[bx]+4,ax ;use original phd parameters.
- mov es:[bx]+8,ax
- mov es:[bx]+12,ax
- mov ax,4b00h
- int 21h
- jc actually_execute_1
- xor ax,ax ;make sure ax is zero if no errors.
- actually_execute_1:
-
- cli ;get our stack back.
- mov ss,cs:our_ss
- mov sp,cs:our_sp
- sti
-
- push ax
-
- mov bx,0ffffh ;now grab all of memory again.
- mov es,phd_seg
- mov ah,4ah ;see how much is available.
- int 21h
- mov ah,4ah ;grab all of it.
- int 21h
-
- push cs ;reset the fatal error address.
- pop ds
- mov dx,offset abort_fatal
- mov ax,2524h
- int 21h
-
- mov ax,33h*256+1 ;turn break checking back off.
- mov dl,0 ; in case someone turned it on.
- int 21h
-
- pop ax
-
- pop es
- pop ds
- assume ds:data, es:data
-
- push ax
- call init_entry
- call paint_screen
- pop ax
- ret
-
-
- init_device:
- push es
- mov dx,offset nul_fcb
- mov ah,0fh ;opfile
- int 21h
- les di,dword ptr nul_fcb.fcb_res+1 ;get the device driver pointer for version 2.
- mov ah,30h ;see if it's really version 2.
- int 21h
- cmp al,2
- je init_device_1 ;it is, we have it.
- les di,dword ptr nul_fcb.fcb_res+2 ;get the device driver pointer for version 3.
- init_device_1:
- mov their_end.offs,di ;remember where we were
- mov their_end.segm,es
- les di,dword ptr es:[di].device_next
- cmp di,-1 ;is this the end of the list?
- jne init_device_1 ;no - keep looking.
- les di,their_end ;get the pointer to the end.
- mov es:[di].device_next.offs,offset our_device
- mov es:[di].device_next.segm,cs
- pop es
-
- ret
-
-
- uninit_device:
- push es
- les di,their_end ;make es:di -> end of the device chain.
- mov ax,-1 ;make this the end again.
- stosw
- stosw
- pop es
- ret
-
-
- ; this is the dispatch table
-
- ; there are 2 entry points to a drive, the strategy entry point
- ; and the interrupt entry point. when z-dos wishes to do an i/o
- ; request, it first calls the strategy routine with a dword pointer
- ; in the es:bx registers. the strategy routine simply saves this
- ; pointer and returns to the system. the interrupt routine is then
- ; called by z-dos. the interrupt routine retrieves the dword pointer
- ; saved by the strategy routine. this pointer is the address of a
- ; "request packet" that contains the information needed to carry
- ; out the i/o request, such as transfer address, byte count, etc.
-
- ; the strategy routine
-
- md_strat proc far
- mov word ptr cs:ptrsav,bx
- mov word ptr cs:ptrsav+2,es ; save es:bx as dword
- ret
- md_strat endp
-
- ; now the interrupt routine.
-
- md_intr proc far
-
- ; save everything
-
- mov cs:their_ss,ss
- mov cs:their_sp,sp
- cli
- mov ss,cs:our_ss
- mov sp,offset mystack
- sti
-
- push ax
- push bx
- push cx
- push dx
- push si
- push di
- push bp
- push es
- push ds
-
- if test_device
- mov si,word ptr cs:ptrsav ; load ax:si with buffer addr
- mov ax,word ptr cs:ptrsav+2 ; load ax:si with buffer addr
- mov cx,(size srh_rw) ;get count of bytes to transfer
- mov es,cs:our_ss
- mov ds,es:textseg
- call insert_string$
- endif
-
- les bx,cs:ptrsav ; es:bx = request packet
- mov cl,es:[bx].srh_cmd ; cl = requested command
- xor ch,ch
- shl cx,1 ; make into word offset
- mov si,cx ; si = pointer to routine
- jmp ss:md_ctab[si] ; go to it
-
- ;* md_in - character input
- ;
- ; md_in reads the number of characters requested into the
- ; address given in the request packet.
- ;
-
- md_in:
- mov cx,es:[bx].crw_cnt ;get the transfer count.
- les di,es:[bx].crw_taddr
- jcxz md_in_2
- md_in_1:
- push es
- push di
- push cx
-
- cmp cs:lf_flag,0 ;do we have a LF to return?
- je get_char_1 ;no.
-
- mov cs:lf_flag,0 ;clear the flag, return LF.
- mov al,LF
- jmp short get_char_3
- get_char_1:
- mov es,cs:our_ss ;prepare to call read_mark.
- mov ds,cs:our_ss
-
- push ds
- mov al,eof_mark ;read the next char.
- call read_mark
- jc get_char_5 ;go if the mark is after the point.
- xor cx,cx ;mark is before point - eof now.
- get_char_5:
- lodsw ;this might not be a valid char.
- pop ds
-
- jcxz get_char_4 ;if no chars left, don't delete any!
-
- push ax ;now delete this char.
- push cx
- mov al,'>'
- call del_to_mark
- pop cx
- pop ax
-
- get_char_4:
-
- stc
- jcxz get_char_2 ;no more chars - return cy.
- cmp cx,2 ;do we have less than two chars?
- jb get_char_3 ;yes - must be a single char.
- cmp ax,CR + LF*256 ;do we have a newline?
- jne get_char_3 ;no - must be a single char.
- mov al,CR ;newline - return CR.
- inc cs:lf_flag ;next time return a LF.
- get_char_3:
- clc
- get_char_2:
- pop cx
- pop di
- pop es
-
- jc md_in_2 ;eof before count satisfied.
- stosb
- loop md_in_1
- md_in_2:
- les bx,cs:ptrsav ; es:bx = packet
- sub es:[bx].crw_cnt,cx ;subtract off the bytes not read.
-
- jmp md_succ
-
-
- ;* md_ichk - non-destructive input check
- ;
- ; md_ichk returns the status of the input queue. a
- ; return of busy indicates queue empty, otherwise
- ; return character at front of queue (without removing
- ; it).
- ;
-
- md_ichk:
- mov es,cs:our_ss ;prepare to call read_mark.
- mov ds,cs:our_ss
-
- mov al,eof_mark ;read the next char.
- call read_mark
- lodsb ;this might not be a valid char.
-
- les bx,cs:ptrsav ; es:bx = packet
- mov es:[bx].cic_char,al
-
- jcxz md_ichk_1 ;no more chars - return busy.
- jmp md_succ
- md_ichk_1:
- mov ax,300h ;return busy.
- jmp md_exit
-
-
- ;* md_istat - input status
- ;
- ; md_istat sets the busy bit if there is a character
- ; ready to be read. if busy is set, the i/o will have
- ; to go to the physical device. if busy is clear, the
- ; read will return quickly.
- ;
-
- md_istat:
- jmp md_succ ; show always ready
-
-
- ;* md_ifl - input queue flush
- ;
- ; flush the input queue
- ;
-
- md_ifl:
- jmp md_succ ; consider it done!
-
-
- ;* md_out - device output
- ;
- ; md_out sends the output to the device
- ;
-
- md_out:
- mov si,es:[bx].crw_taddr.offs ; load ax:si with buffer addr
- mov ax,es:[bx].crw_taddr.segm ; load ax:si with buffer addr
- mov cx,es:[bx].crw_cnt ;get count of bytes to transfer
- mov es,cs:our_ss
- mov ds,es:textseg
- call insert_string$
- jmp md_succ ;show success.
-
-
- ;* md_ostat - output status
- ;
- ; md_ostat returns the status of the device. if busy
- ; is a 1, output will have to wait for device ready. if
- ; busy is a 0, output will go directly to device with
- ; no waiting.
- ;
-
- md_ostat:
- jmp md_succ ; output device is ready
-
-
- ; the routines exit through md_succ if no error, or md_fail if
- ; an error has occured
-
- md_succ:
- mov ax,100h ; show 'done' with no errors.
- jmp short md_exit
-
- md_unk:
- mov al,3 ; unknown command
- md_fail:
- mov ah,80h ; add the error bits
- md_exit:
- les bx,cs:ptrsav ; es:bx = packet
- mov es:srh_status[bx],ax ; save the status
-
- if test_device
- mov si,word ptr cs:ptrsav ; load ax:si with buffer addr
- mov ax,word ptr cs:ptrsav+2 ; load ax:si with buffer addr
- mov cx,(size srh_rw) ;get count of bytes to transfer
- mov es,cs:our_ss
- mov ds,es:textseg
- call insert_string$
-
- les bx,cs:ptrsav
- mov si,es:[bx].crw_taddr.offs ; load ax:si with buffer addr
- mov ax,es:[bx].crw_taddr.segm ; load ax:si with buffer addr
- mov cx,es:[bx].crw_cnt ;get count of bytes to transfer
- jcxz md_exit_1
- mov es,cs:our_ss
- mov ds,es:textseg
- call insert_string$
- md_exit_1:
-
- mov si,offset crlf_string ; load ax:si with buffer addr
- mov ax,ss ; load ax:si with buffer addr
- mov cx,2 ;get count of bytes to transfer
- mov es,cs:our_ss
- mov ds,es:textseg
- call insert_string$
-
- endif
-
- pop ds
- pop es
- pop bp
- pop di
- pop si
- pop dx
- pop cx
- pop bx
- pop ax
- cli
- mov ss,cs:their_ss
- mov sp,cs:their_sp
- sti
- ret
-
- md_intr endp
-
-
- public get_next_buffer
- get_next_buffer:
- push ds
- mov ds,textseg
- assume ds:bufseg
- mov ax,next_buffer
- pop ds
- assume ds:data
- ret
-
-
- public init_all_buffers
- init_all_buffers:
- ;enter with ax=>first paragraph of available memory, bx=> first paragraph of
- ; unavailable memory.
- ;exit with cy if no buffer available.
- mov first_buffer,ax
- mov last_para,bx
- mov textseg,ax
- mov dx,ax
- call init_buffer
- ret
-
- public buffer_allocate
- buffer_allocate:
- ;entry:
- ; case cx of
- ; -1..-32768: report the current buffer number.
- ; exit: ax=current buffer number.
- ; 0: create a new buffer.
- ; exit: ax=new buffer number if enough memory, ax=0 otherwise.
- ; 1..32767:
- ; entry: cx=buffer number to select, ax=0 for read/write buffer.
- ; exit: ax=buffer number if it exists, ax=0 otherwise.
- jcxz buffer_allocate_2
- or cx,cx ;if cx<0, return buffer number.
- js buffer_allocate_4_j
- push cx
- push ax
- call find_buffer
- jc buffer_allocate_5 ;buffer not found.
-
- push ds
- push dx
- mov ds,dx ;get the current buffer back.
- call select_buffer
- pop dx
- pop ds
-
- pop cx ;pushed as ax =0 if read/write buffer.
- pop ax ;pushed as cx (buffer number).
- or cx,cx ;read only buffer?
- jne buffer_allocate_4 ;yes - we're done.
- push ax
- call close_up_buffers
- pop cx ;pushed as ax
- mov dx,first_buffer ;find the buffer again.
- assume ds:bufseg
- buffer_allocate_6:
- mov ds,dx
- mov dx,next_buffer
- loop buffer_allocate_6
- mov dx,ds ;get the current buffer back.
- push es
- pop ds
- assume ds:data
- call open_up_buffers
- buffer_allocate_4_j:
- jmp short buffer_allocate_4
- buffer_allocate_5:
- add sp,4 ;conserve the stack.
- mov ax,0 ;buffer not found.
- jmp short buffer_allocate_1
- buffer_allocate_2:
- call close_up_buffers ;close all the buffers up.
- mov ds,dx ;get the para of the last buffer.
- assume ds:bufseg
- call buffer_paragraphs ;compute the size of it.
- add dx,cx ;find the end of it.
- call init_buffer
- mov ax,0
- jc buffer_allocate_1 ;not enough memory.
- mov next_buffer,dx ;point previous buffer to this one.
- buffer_allocate_4:
- mov bx,textseg
- call buffer_number ;return number in ax.
- buffer_allocate_1:
- push es
- pop ds
- assume ds:data
- ret
-
-
- public buffer_insert
- buffer_insert:
- ;enter with al=mark, cx=buffer number.
- ;insert the text between point and mark from the given buffer.
- ;exit with nc if ok, cy if the given buffer doesn't exist, or the specified
- ; text won't fit.
- push textseg
- push ax
- call find_buffer ;find their buffer.
- assume ds:bufseg
- jc buffer_insert_1 ;not found.
-
- push ds
- push dx
- mov ds,dx ;get the current buffer back.
- call select_buffer
- pop dx
- pop ds
-
- pop ax
-
- push dx
- call read_mark
- pop dx
-
- pop ds ;make ds->our buffer.
- push dx ;save ->their buffer.
- push cx
- call select_buffer
- pop cx
- pop ax ;pushed as dx.
- call insert_string$
- jmp short buffer_insert_2
- buffer_insert_1:
- add sp,4 ;get rid of mark, textseg.
- stc
- buffer_insert_2:
- push es ;restore ds.
- pop ds
- assume ds:data
- ret
-
-
- public buffer_number
- buffer_number:
- ;enter with bx=paragraph of buffer.
- ;exit with ax=number of buffer.
- push ds
- assume ds:bufseg
- mov dx,first_buffer
- xor ax,ax
- buffer_number_1:
- inc ax
- mov ds,dx
- cmp dx,bx ;is this the one we're looking for.
- mov dx,next_buffer ;in any case, get the next buffer
- jne buffer_number_1
- buffer_number_2:
- pop ds
- assume ds:data
- ret
-
-
- public succ_buffer
- succ_buffer:
- ;enter with bx=buffer number.
- ;exit with nc, bx=next nonempty buffer, dx=segment of next buffer,
- ; cy if no other buffers or all other buffers are empty.
- push ds
- mov cx,bx
- mov ax,bx
- mov dx,first_buffer
- assume ds:bufseg
- succ_buffer_2:
- cmp dx,last_para ;at the end?
- stc
- je succ_buffer_3 ;yes - don't change the buffer number.
- mov ds,dx
- mov dx,next_buffer
- loop succ_buffer_2
- succ_buffer_0:
- cmp dx,last_para ;are we at the end?
- jne succ_buffer_1
- mov ds,first_buffer ;yes - start from the beginning again.
- mov dx,next_buffer ;skip the first buffer.
- mov ax,1
- succ_buffer_1:
- inc ax ;preincrement.
- cmp ax,bx ;have we wrapped around?
- stc
- je succ_buffer_3 ;yes - exit.
- mov ds,dx ;get the new segment to try.
- mov dx,topbot ;is the next buffer empty?
- sub dx,toptop
- add dx,botbot
- sub dx,bottop
- mov dx,next_buffer
- je succ_buffer_0 ;yes - keep looking.
- mov bx,ax ;return the new buffer number.
- clc
- succ_buffer_3:
- mov dx,ds ;remember the segment.
- assume ds:data
- pop ds
- ret
-
-
- ;the private routines start here.
-
-
- open_up_buffers:
- ;enter with dx=paragraph of buffer to open up.
- mov bx,last_para ;search for the last buffer in memory.
- mov cx,bx ;new next buffer is the same as the old.
- assume ds:bufseg
-
- ; search for the buffer whose next_buffer is in bx. We start with
- ; bx=last_para, then we work our way down through the buffers.
- ; We use cx to hold the new next buffer for the buffer we're looking for.
-
- open_up_buffers_1:
- mov ax,first_buffer
- open_up_buffers_2:
- mov ds,ax ;switch to this buffer.
- mov ax,next_buffer ;is this the last one?
- cmp ax,bx
- jne open_up_buffers_2 ;no - keep looking.
-
- ; now that we have the buffer we're looking for, tell it where the next
- ; buffer is in memory.
-
- mov next_buffer,cx
- mov bx,ds ;get the current buffer.
- cmp bx,dx ;is it the one we want?
- je open_up_buffers_3 ;yes - go open it.
- ;ds, bx now has the buffer to move up in memory.
- mov ax,cx ;get the destination paragraph.
- call move_buffer_higher ;move the buffer up.
- mov cx,ax ;save the new destination paragraph.
- mov bx,ds ;save the "next" buffer.
- jmp open_up_buffers_1
- open_up_buffers_3:
- call open_buffer ;open the buffer in ds.
- push es
- pop ds
- assume ds:data
- ret
-
-
- compact_buffers:
- ;move all the buffers as low in memory as they'll go.
- ;exit with dx=paragraph of last buffer in memory.
- push ds
-
- mov ds,first_buffer
- assume ds:bufseg
- compact_buffers_4:
- mov bx,next_buffer
- cmp bx,last_para ;was this the last buffer in memory?
- je compact_buffers_3 ;yes - we're done.
-
- call move_buffer_lower ; ax=paragraph to move it to.
- jmp compact_buffers_4
- compact_buffers_3:
- mov dx,ds ;return the para of the last buffer.
- pop ds
- assume ds:data
- ret
-
-
-
- close_up_buffers:
- ;close the buffer that is open.
- ;exit with dx=paragraph of last buffer in memory.
- push ds
-
- mov ds,first_buffer
- assume ds:bufseg
- close_up_buffers_1:
- mov bx,next_buffer
- cmp bx,last_para ;was this the last buffer in memory?
- je close_up_buffers_2 ;yes - we're done.
-
- call close_buffer ;close this buffer.
-
- call move_buffer_lower ; ax=paragraph to move it to.
-
- jmp close_up_buffers_1
-
- close_up_buffers_2:
- mov dx,ds ;return the para of the last buffer.
- pop ds
- assume ds:data
- ret
-
-
- public find_buffer
- find_buffer:
- ;enter with cx=buffer number.
- ;exit with nc, dx set to that buffer if it exists, cy otherwise.
- mov dx,first_buffer
- assume ds:bufseg
- find_buffer_1:
- cmp dx,last_para ;at the end?
- je find_buffer_2
- mov ds,dx
- mov dx,next_buffer
- loop find_buffer_1
- mov dx,ds ;get the current buffer back.
- push es
- pop ds
- clc
- ret
- find_buffer_2:
- push es ;restore the data segment.
- pop ds
- assume ds:data
- stc
- ret
-
-
- code ends
-
-
- code segment byte public
- ;all the code in this segment is entered with ds=bufseg, es=data
- assume cs:code, ds:bufseg, es:data
-
- ;the following externs are in 'memory'
- extrn init_vars$: near
- extrn insert_string$: near
-
- ;the following externs are in 'marks'
- extrn init_marks: near
-
- ;the following externs are in 'redisp'
- extrn adjust_buffers: near
-
-
- select_buffer:
- ;enter with ds=buffer to select.
- mov textseg,ds ;save the new current buffer.
- mov ax,botbot
- sub ax,toptop
- mov dx,0
- mov cx,100
- div cx
- mov memsize,ax
- ret
-
-
- init_buffer:
- ;initialize and opens the buffer whose segment is in dx.
- ;exit with cy if there's not enough memory for a new buffer.
- mov ax,(offset bufseg_size)+0fh ;get size of bufseg rounded up.
- shr ax,1
- shr ax,1
- shr ax,1
- shr ax,1
- add ax,dx
- cmp ax,last_para ;is there enough memory for new buffer?
- jae init_buffer_1 ;no.
- push ds
- mov ds,dx
- mov bx,last_para
- mov next_buffer,bx
- push dx
- call init_vars$ ;init most everything
- call init_marks ;init the rest.
- call open_buffer ;open this one up.
- pop dx
- pop ds
- clc
- ret
- init_buffer_1:
- stc
- ret
-
-
- close_buffer:
- ;close the buffer in ds.
- mov ax,topbot ;if topbot<>bottop, then it's open.
- cmp ax,bottop
- je close_buffer_1 ;if it's already closed, we're done.
- mov di,topbot
- if 1
- mov ax,ds ;if it's open and it's not the first
- cmp ax,first_buffer ; buffer, close it.
- jne close_buffer_2
- add di,2000 ;leave at most this many free bytes
- cmp di,bottop ; in buffer one.
- jae close_buffer_1 ;but if we can't leave that many, don't bother
- close_buffer_2:
- endif
- mov si,bottop
- mov bottop,di ;save the new bottop.
- mov cx,botbot
- sub cx,si ;same as sub cx,bottop
- add cx,2 ;include the trailing newline.
- push es
- push ds
- pop es
- rep movsb
- pop es
- sub di,2 ;don't include the newline in botbot.
- mov botbot,di
- close_buffer_1:
- ret
-
-
- open_buffer:
- ;select the buffer in ds.
- ;enter with ds=buffer to open.
- mov bx,next_buffer
- mov ax,ds
- sub bx,ax ;compute the available paragraphs
- cmp bx,1000h ;don't use more than 1000h of them.
- jb open_buffer_1
- mov bx,1000h
- open_buffer_1:
- mov di,bx
- add bx,ax ;make bx=first unused para.
- mov cl,04 ;change di from paras into bytes
- shl di,cl
- push es
- push ds
- pop es
- mov si,botbot
- std
- mov cx,botbot
- sub cx,bottop
- inc si
- dec di
- movsb ;move the LF
- mov botbot,di
- movsb ;move the CR
- rep movsb
- inc di
- mov bottop,di
- cld
- pop es
- call select_buffer
- ret
-
-
- move_buffer_higher:
- ;move a buffer higher in memory, closing open buffers.
- ;enter with ds,bx=buffer to move, ax=first unavailable paragraph
- ;exit with ax=paragraph that buffer was moved to (new first unavailable para).
- ;don't destroy dx.
- push ax
- call close_buffer
- pop ax
-
- push es
- call buffer_paragraphs
- sub ax,cx ;find new destination para
- call adjust_buffers
- mov es,ax
- assume es:bufseg
- mov si,0
- mov di,si
-
- mov cx,botbot ;get the last location used in a buffer,
- add cx,2-1 ; add two for newline and compensate for moving backwards.
- add si,cx
- add di,cx
- ; inc cx ;don't do this and the following dec
- ; ; because it wastes time.
- std
- movsb ;always move one byte.
- ; dec cx ;this takes care of moving 65536 bytes.
- rep movsb
- cld
- pop es
- assume es:data
- ret
-
-
- move_buffer_lower:
- ;move a buffer lower in memory.
- ;enter with ds=buffer before the one to be lowered.
- ;exit with ds=new location of lowered buffer.
- call buffer_paragraphs
-
- mov ax,ds ;get the base of this buffer.
- add ax,cx ;get the end of this buffer.
- mov bx,next_buffer
- mov next_buffer,ax ;save the pointer to the next buffer.
- mov ds,bx ;get paragraph of buffer to move.
-
- cmp ax,bx ;leave if the buffer is already there.
- je move_buffer_lower_1
- call adjust_buffers
- push es
- mov es,ax
- mov si,0
- mov di,si
- mov cx,botbot ;get the last location used in a buffer.
- add cx,2 ;round up to next paragraph, add two for newline.
- movsb ;always move one byte.
- dec cx ;this takes care of moving 65536 bytes.
- rep movsb
- pop es
- mov ds,ax ;get new para of just moved buffer.
- move_buffer_lower_1:
- ret
-
-
- buffer_paragraphs:
- ;compute the number of paragraphs used by a buffer.
- ;enter with ds=buffer
- ;exit with cx=number of paragraphs.
- mov cx,botbot
- add cx,0fh+2 ;round up to next paragraph plus two for newline
- rcr cx,1 ;ensure that 65536 bytes becomes
- shr cx,1 ; 1000h paragraphs.
- shr cx,1
- shr cx,1
- ret
-
-
- code ends
-
- end